<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<meta http-equiv="x-UA-Compatible" content="ie=Edge">
   	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Crafty - 通用组件</title>
	<link rel="shortcut icon" href="../favicon.ico">
	<link type="text/css" rel="stylesheet" href="../craftyjs-site.css" />
</head>
<body>
	<div id = "header-background"> </div>
	<div id = "page-frame">
	<div id="header">
		<nav class="navbar">
  			<div class="container-fluid">
  				<div class="navbar-header">
  					<a class="navbar-brand" href="../"> <img class="logo" src="../images/text-logo.png" /> </a>
  					
				</div>
				<div class="collapse navbar-collapse navbar-right" id="bs-example-navbar-collapse-1">
					<ul class="nav navbar-nav">
						<li><a href="../">首页</a></li>
						<li><a href="../getting-started/">快速开始</a></li>
						<li><a href="../documentation/">文档</a></li>
						<li><a href="../api/">API</a></li>
						<li><a href="../components/">组件</a></li>
						<li class="emph"><a href="../#install">下载</a></li>
					</ul>
				</div>
			</div>
		</nav>
	</div>


	<div id="main">
		<div id="content" class="container">
			
<div id="docs">
	<div id='doc-nav'>
		<ul id='doc-level-one'>
			<li>
				Topics
				<ul>
					<li>
						<a href='../documentation/'>
							文档
						</a>
					</li>
					<li>
						<a href='../documentation/entities.html'>
							实体
						</a>
					</li>
					<li>
						<a href='../documentation/events.html'>
							事件
						</a>
					</li>
					<li>
						<a href='../documentation/components.html'>
							组件
						</a>
					</li>
					<li>
						<a href='../documentation/2d.html'>
							2D绘图
						</a>
					</li>
					<li>
						<a href='../documentation/text.html'>
							文本
						</a>
					</li>
					<li>
						<a href='../documentation/keyboard.html'>
							键盘
						</a>
					</li>
					<li>
						<a href='../documentation/mouse.html'>
							鼠标
						</a>
					</li>
					<li>
						<a href='../documentation/sound.html'>
							声音
						</a>
					</li>
					<li>
						<a href='../documentation/sprites.html'>
							精灵
						</a>
					</li>
					<li>
						<a href='../documentation/scenes.html'>
							场景
						</a>
					</li>
					<li>
						<a href='../documentation/gameloop.html'>
							游戏循环
						</a>
					</li>
				</ul>
			</li>
		</ul>
	</div>
	<div id='doc-content' class="markdown">
		

		<h2> 通用组件 </h2>
<p>Crafty 有一些内置的组件，但创建自己的组件是一种很好的组织你游戏的方式。</p>
<p>在几个例子中，我们创建了彩色方块，并且我们重复了很多代码。例如，下面的代码创建两个正方形:</p>
<pre><code><span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"2D, Canvas, Color"</span>)
    .attr({<span class="hljs-attr">x</span>:<span class="hljs-number">10</span>, <span class="hljs-attr">y</span>:<span class="hljs-number">10</span>, <span class="hljs-attr">w</span>:<span class="hljs-number">30</span>, <span class="hljs-attr">h</span>:<span class="hljs-number">30</span>})
    .color(<span class="hljs-string">"red"</span>);
<span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"2D, Canvas, Color"</span>)
    .attr({<span class="hljs-attr">x</span>:<span class="hljs-number">150</span>, <span class="hljs-attr">y</span>:<span class="hljs-number">100</span>, <span class="hljs-attr">w</span>:<span class="hljs-number">30</span>, <span class="hljs-attr">h</span>:<span class="hljs-number">30</span>})
    .color(<span class="hljs-string">"green"</span>);</code></pre>
<p>当然，你可以创建一个方法来方便地创建一个方块。但 Crafty 的方法是使用组件。定义一个组件使用 <a href="../api/Crafty-c.html"><code>Crafty.c</code></a>。</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-comment">// This function will be called when the component is added to an entity</span>
    <span class="hljs-comment">// So it sets up the things that both our entities had in common</span>
    init: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">this</span>.addComponent(<span class="hljs-string">"2D, Canvas, Color"</span>);
        <span class="hljs-keyword">this</span>.w = <span class="hljs-number">30</span>;
        <span class="hljs-keyword">this</span>.h = <span class="hljs-number">30</span>;
    },

    <span class="hljs-comment">// This function will be called when the component is removed from an entity</span>
    <span class="hljs-comment">// or right before entity is destroyed.</span>
    <span class="hljs-comment">// Useful for doing custom cleanup.</span>
    remove: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-comment">// This function serves for logging.</span>
        <span class="hljs-comment">// Once your game is release ready you can disable logging</span>
        <span class="hljs-comment">// by setting Crafty.loggingEnabled to false</span>
        Crafty.log(<span class="hljs-string">'Square was removed!'</span>);
    },

    <span class="hljs-comment">// Our two entities had different positions, </span>
    <span class="hljs-comment">// so we define a method for setting the position</span>
    place: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">x, y</span>) </span>{
        <span class="hljs-keyword">this</span>.x = x;
        <span class="hljs-keyword">this</span>.y = y;

        <span class="hljs-comment">// There's no magic to method chaining.</span>
        <span class="hljs-comment">// To allow it, we have to return the entity!</span>
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
    }
})</code></pre>
<p><code>Crafty.c</code> 需要两个参数: 第一个参数是组件的名字, 第二个参数是一个对象，用来定义方法和属性。当一个组件添加到实体，它的所有属性和方法都会拷贝到这个实体上。  The <code>init</code> 方法是比较特殊的,它在组件添加到实体时被调用。你也可以定义一个 <code>remove</code> 函数，它会在实体移除组件或者实体销毁时被调用。</p>
<p>根据这些定义，我们来从新组织一下我们的代码：</p>
<pre><code><span class="hljs-keyword">var</span> sq1 = Crafty.e(<span class="hljs-string">"Square"</span>)
    .place(<span class="hljs-number">10</span>, <span class="hljs-number">10</span>)
    .color(<span class="hljs-string">"red"</span>);

<span class="hljs-keyword">var</span> sq2 = Crafty.e(<span class="hljs-string">"Square"</span>)
    .place(<span class="hljs-number">150</span>, <span class="hljs-number">100</span>)
    .color(<span class="hljs-string">"green"</span>);</code></pre>
<p>我们已经抽取了这两个实体的共同点，并把它放在我们组件的 <code>init</code> 函数中。这是一种在实体间重用代码的常见方法。在某种程度上，它有点像&quot;Square&quot;继承了其他组件的方法；通过给一个实体添加&quot;Square&quot;，我们自动地得到所有&quot;Color&quot;的方法。</p>
<p>记住，方法的链式调用(调用 <code>e.place().color()</code>)只是因为我们明确地将 <code>this</code> 从我们的自定义方法返回。忘记这样做可能是错误的常见来源，所以如果您难以确定 “方法未定义” 的错误根源时，请记住这一点。</p>
<h2 id="shorthand-for-adding-components">添加组件的简写方法</h2>
<p>要快速声明在自定义组件初始化之前需要添加到实体中的其他组件的列表，可以使用 <code>required</code> 字段：</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-comment">// These components will be added to any entity with the "Square" component before it is initialized</span>
    required: <span class="hljs-string">"2D, Canvas, Color"</span>
});</code></pre>
<h2 id="shorthand-for-binding-events">绑定事件的简写方法</h2>
<p>初始化组件时绑定事件，移除组件时解绑事件，这是很常见的。为了简化操作，你可以在组件对象中直接声明事件处理函数:</p>
<pre><code>Crafty.c(<span class="hljs-string">"Square"</span>, {
    <span class="hljs-attr">required</span>: <span class="hljs-string">"2D, Canvas, Color"</span>,

    <span class="hljs-comment">// These handlers will be bound upon init, and unbound when the component is removed</span>
    events: {
        <span class="hljs-comment">// bind the given function to the blush event</span>
        <span class="hljs-string">"Blush"</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
            <span class="hljs-keyword">this</span>.color(<span class="hljs-string">"pink"</span>);
        },

        <span class="hljs-comment">// Bind the named function to the "Blanch" event.</span>
        <span class="hljs-string">"Blanch"</span>: <span class="hljs-string">"turnWhite"</span>
    },

    <span class="hljs-attr">turnWhite</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>)</span>{
        <span class="hljs-keyword">this</span>.color(<span class="hljs-string">"white"</span>);
    }
});</code></pre>
<p>你可以使用一个函数对象，也可以使用组件具有的函数名称。(当你在超过一个的事件上下文中引用方法时后一种方式通常更有用。)</p>
<h2 id="the-nitty-gritty">实现细节</h2>
<p>有时候你可能需要知道组件是如何添加到实体。(如果组件之前已经添加到实体，再次添加则不产生任何作用)</p>
<ul>
<li>首先一个表示组件已添加的标识会被设置。</li>
<li>然后组件的所有属性会被拷贝到实体，如果属性已经存在则覆盖。</li>
<li>如果属性是对象或者数组，则只会拷贝引用。</li>
<li>最后，组件的 init 方法会被调用。</li>
</ul>
<h3 id="the-shared-object-trap">共享对象陷阱</h3>
<p>如上所述，对象和数组是通过引用复制的。如果你不小心，这会引起意想不到的行为：</p>
<pre><code>Crafty.c(<span class="hljs-string">"MyComponent"</span>, {
    <span class="hljs-attr">sharedObject</span>: {<span class="hljs-attr">a</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">b</span>:<span class="hljs-number">2</span>}
});
<span class="hljs-keyword">var</span> e1 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
<span class="hljs-keyword">var</span> e2 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
e1.sharedObject.a = <span class="hljs-number">5</span>;
<span class="hljs-built_in">console</span>.log(e2.sharedObject.a); <span class="hljs-comment">// Logs 5!</span></code></pre>
<p>如果你希望一个属性只属于一个对象，不希望在两个实体间共享，解决办法是在 init 方法中创建一个新对象:</p>
<pre><code>Crafty.c(<span class="hljs-string">"MyComponent"</span>, {
    <span class="hljs-attr">init</span>: <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"></span>) </span>{
        <span class="hljs-keyword">this</span>.myObject = {<span class="hljs-attr">a</span>:<span class="hljs-number">1</span>, <span class="hljs-attr">b</span>:<span class="hljs-number">2</span>};
    }
});
<span class="hljs-keyword">var</span> e1 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
<span class="hljs-keyword">var</span> e2 = Crafty.e(<span class="hljs-string">"MyComponent"</span>);
e1.myObject.a = <span class="hljs-number">5</span>;
<span class="hljs-built_in">console</span>.log(e2.myObject.a); <span class="hljs-comment">// Logs the original value of 1</span></code></pre>
	</div>
</div>
			
		</div>
	</div>
	<div class="clearer"></div>
	<div id="footer">
		<div id="contact">
			<a href="https://groups.google.com/forum/#!forum/craftyjs">
				<img src="../images/google.png" />
				google groups</a>
			<a href="mailto:starwed@gmail.com">
				<img src="../images/email.png" />
				starwed@gmail.com</a>
			<a href="https://github.com/craftyjs/Crafty">
				<img src="../images/github.png" />
				github</a>
		</div>
		<ul>
			<li><a href="../">首页</a></li>
				<li><a href="../getting-started/">快速开始</a></li>
				<li><a href="../documentation/">文档</a></li>
				<li><a href="../api/">API</a></li>
				<li><a href="../components/">组件</a></li>
				<li class="emph"><a href="../#install">下载</a></li>
		</ul>
		<p>
			&copy; Crafty 2010-2015. Crafty is distributed under the <a href="http://en.wikipedia.org/wiki/MIT_License">MIT License</a>.
		</p>
	</div>
</div>
</body>
</html>
